package com.um.jdy.mp.device.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.um.jdy.common.charge.enums.OrderEnum;
import com.um.jdy.common.charge.service.OrderService;
import com.um.jdy.common.device.code.DeviceCode;
import com.um.jdy.common.device.entity.dto.PileDTO;
import com.um.jdy.common.device.entity.po.Fee;
import com.um.jdy.common.device.entity.po.Gun;
import com.um.jdy.common.device.entity.po.Pile;
import com.um.jdy.common.device.entity.po.Station;
import com.um.jdy.common.device.entity.vo.FeePbPriceVO;
import com.um.jdy.common.device.entity.vo.GunVO;
import com.um.jdy.common.device.entity.vo.PileVO;
import com.um.jdy.common.device.enums.DeviceEnum;
import com.um.jdy.common.device.service.FeeService;
import com.um.jdy.common.device.service.GunService;
import com.um.jdy.common.device.service.PileService;
import com.um.jdy.common.device.service.StationService;
import com.um.jdy.common.member.enums.MemberEnum;
import com.um.jdy.common.platform.code.PartnersCode;
import com.um.jdy.common.platform.code.PlatformCode;
import com.um.jdy.common.platform.entity.po.Merchant;
import com.um.jdy.common.platform.service.MerchantService;
import com.um.jdy.mp.device.entity.dto.DeliveryDTO;
import com.um.jdy.mp.device.entity.dto.DeviceDTO;
import com.um.jdy.mp.device.entity.vo.DeviceCenterVO;
import com.um.jdy.mp.device.entity.vo.DeviceCodeVo;
import com.um.jdy.mp.device.entity.vo.DeviceGunVO;
import com.um.jdy.mp.device.entity.vo.PileItemVO;
import com.um.jdy.mp.user.service.SessionUserService;
import com.um.jdy.rpc.enums.DeviceTypeEnum;
import com.um.jdy.rpc.ev.confirmation.SetPriceModelConfirmation;
import com.um.jdy.rpc.ev.enums.ConfirmationStatus;
import com.um.jdy.rpc.factory.ServiceFactory;
import com.um.springboot.starter.code.CommonCode;
import com.um.springboot.starter.entity.Page;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.orm.entity.Response;
import com.um.springboot.starter.orm.manager.BaseManager;
import com.um.springboot.starter.orm.params.ListParams;
import com.um.springboot.starter.orm.params.PageParams;
import com.um.springboot.starter.utils.StringUtil;
import com.um.springboot.starter.utils.UMBeanUtils;
import com.um.springcloud.dubbo.cluster.DeviceKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Component
@Slf4j
public class DeviceManager extends BaseManager<PileService> {

    @Autowired
    FeeService feeService;

    @Autowired
    StationService stationService;

    @Autowired
    OrderService orderService;

    @Autowired
    GunService gunService;

    @Autowired
    MerchantService merchantService;

    @Autowired
    SessionUserService sessionUserService;

    @Autowired
    ServiceFactory serviceFactory;


    /**
     * 查询设备管理中心
     *
     * @return
     */
    public Response getCenter() {

        DeviceCenterVO deviceCenterVO = service.getViewModel("get_device_center",DeviceCenterVO.class,new Object[]{sessionUserService.getTokenUserId()});
        System.out.print("deviceCenterVO===============>" + deviceCenterVO);
//
//        deviceCenterVO.setTotalCount(deviceCenterVO.getOfflineCount()+deviceCenterVO.getOnlineCount()+deviceCenterVO.getUnactiveCount());

        return Response.success(deviceCenterVO);
    }

    public Response<List<PileItemVO>> list(ListParams params) {
        params.getCondition().put("p.com_id", getComId());
        params.getCondition().put("m.platform_merchant_id", sessionUserService.getTokenUserId());
        List list = service.getCMSViewModelListBySqlName("get_pile_list", PileItemVO.class, params.getProperties(), params.getValues(), params.getRangeEntitys(), params.getOrderNames(), params.getSortOns());

        return Response.success(list);
    }

    /**
     * 分页查询桩
     *
     * @param params
     * @return
     */
    public Response<Page<PileItemVO>> page(PageParams params) {
        Page<PileItemVO> page = new Page();
        page.setPageNo(params.getPageNo());
        page.setPageSize(params.getPageSize());

        params.getCondition().put("p.com_id", getComId());
        params.getCondition().put("m.platform_merchant_id", sessionUserService.getTokenUserId());

        page = service.getCMSViewModelPageBySqlName(page, "get_pile_page", "get_pile_count",
                PileItemVO.class, params.getProperties(), params.getValues(), params.getRangeEntitys(), params.getOrderNames(), params.getSortOns());
        return Response.success(page);
    }

    /**
     * 查询设备充电口列表
     *
     * @param pileId
     * @return
     */
    public Response<List<GunVO>> getGunList(String pileId) {

        checkPermission(pileId);

        List<Gun> list = gunService.getList("device_pile_id", pileId, "port", "asc");
        return Response.success(UMBeanUtils.copyBeanList(list, GunVO.class));
    }

    /**
     * 修改充电桩名称
     *
     * @param devicePileId
     * @param name
     */
    public Response updateName(String devicePileId, String name) {

        Pile entity = service.getEntity(new String[]{"platform_merchant_id", "device_pile_id"}, new Object[]{sessionUserService.getTokenUserId(), devicePileId});

        if (null == entity) {
            throw new ServiceException(DeviceCode.NoPile);
        }

        entity.setName(name);
        boolean result = service.save(entity);
        return result ? Response.success() : Response.failed();
    }

    private Pile getDeviceMap(String code) {
        if (StrUtil.isBlank(code)) {
            throw new ServiceException(DeviceCode.NoDevice);
        }

        String user_type = sessionUserService.getTokenUser().getType();

        if(!user_type.equals("merchant")) {
            throw new ServiceException(PlatformCode.NotMerchant);
        }

        Pile pile = service.getEntityBySqlName("get_pile_info", new Object[]{code, sessionUserService.getTokenUser().getPlatformMerchantId()});

        if (pile == null) {
            throw new ServiceException(DeviceCode.NoDevice);
        }
//        if (!DeviceEnum.PileStatus.NORMAL.name().equals(pile.getStatus())) {
//            throw new ServiceException("设备异常，请稍后再试！");
//        }

        return pile;
    }



    /**
     * 分页查询设备库存
     *
     * @param pageParams
     * @return
     */
    public Response<Page<PileVO>> getPileStoragePage(PageParams pageParams) {
        Page<PileVO> page = new Page<>();
        page.setPageNo(pageParams.getPageNo());
        page.setPageSize(pageParams.getPageSize());
        pageParams.getCondition().put("d.com_id", getComId());
        Merchant merchant = sessionUserService.getTokenUser();

        if(merchant.getType().equals("merchant")) {
            pageParams.getCondition().put("d.platform_merchant_id", merchant.getPlatformMerchantId());
        }

        String sqlName = "get_pile_storage_page";
        String sqlAllName = "get_pile_storage_count";

        page = service.getCMSViewModelPageBySqlName(page, sqlName, sqlAllName, PileVO.class, pageParams.getProperties(), pageParams.getValues(),
                pageParams.getRangeEntitys(), pageParams.getOrderNames(), pageParams.getSortOns());
        return Response.success(page);
    }

    /**
     * 返回符合平台的设备编码
     * @param codeAndGunNo
     * @return
     */
    private String getAvaliableCode(String codeAndGunNo){
        String code = codeAndGunNo;
        //汽车桩：桩号14位，枪号2位的规则解析
        if(codeAndGunNo.length() == 16) {
            code = StrUtil.subPre(codeAndGunNo,14);
        }

        //汽车桩：桩号10位，枪号1位的规则解析
        if(codeAndGunNo.length() == 11) {
            code = StrUtil.subPre(codeAndGunNo,10);
        }

        return code;
    }

    /**
     * 扫描二维码/输入编码
     *
     * @param code
     * @return
     */
    public Response<PileVO> scanCode(String code) {
        code = getAvaliableCode(code);

        Pile pile = getDeviceMap(code);
        try {
            //扫码时查询一下端口状态
            //serviceFactory.getRpcEVDeviceService(pile.getVender()).reqQueryPorts(code, String.valueOf(pile.getImei()));
            return Response.success(BeanUtil.toBean(pile, PileVO.class));
        } catch (Exception ex) {
            log.error("查询设备端口状态失败：{}，{}", StringUtil.getTrim(pile.getImei()), code);
        }
        return Response.failed();
    }

    /**
     * 扫码，库存设备
     *
     * @param code
     * @return
     */
    public Response<PileVO> scanInventory(String code) {
        if(StringUtil.isEmpty(code)) {
            throw new ServiceException(DeviceCode.DeviceCodeRequired);
        }

        code = getAvaliableCode(code);

        String[] properties = new String[]{"platform_merchant_id", "device_station_id"};
        Object[] values;

        String user_type = sessionUserService.getTokenUser().getType();
        if(user_type.equals("merchant")) {
            values = new Object[]{sessionUserService.getTokenUser().getPlatformMerchantId(), ""};
        }else {
            throw new ServiceException(PlatformCode.NotMerchant);
        }

        PileVO pileVO = service.getCMSViewModelBySqlName("get_inventory_pile_info", PileVO.class, properties, values, new ArrayList<>(), new Object[]{code});

        if(pileVO == null) {
            Pile pile = service.getEntity("code", code);

            if(pile == null) {
                log.error("设备不存在：pile is null");
                throw new ServiceException(DeviceCode.NoDevice);
            }

            if(StringUtil.isEmpty(pile.getImei())) {
                log.error("设备不存在:imei is empty");
                throw new ServiceException(DeviceCode.NoDevice);
            }

            if(user_type.equals("merchant")) {
                if(!pile.getPlatformMerchantId().equals(sessionUserService.getTokenUser().getPlatformMerchantId())) {
                    log.error("设备不存在:运营商ID不相等");
                    throw new ServiceException(DeviceCode.NoDevice);
                }
            }

            if(!pile.getDeviceStationId().equals("")) {
                throw new ServiceException(DeviceCode.DeviceHasBind);
            }

        }

        return Response.success(pileVO);
    }

    /**
     * 设备绑定
     *
     * @param deviceDTO
     */
    public void bind(DeviceDTO deviceDTO) {
        //检查设备
        Pile pile = service.getEntity(new String[]{"device_pile_id"},
                new Object[]{deviceDTO.getDeviceId()});
        if (null == pile) {
            throw new ServiceException(DeviceCode.NoPile);
        }

        //检查绑定情况
        if (!StringUtil.isEmpty(pile.getPlatformMerchantId())
                && !pile.getPlatformMerchantId().equals(sessionUserService.getTokenUserId())) {
            throw new ServiceException(DeviceCode.PileIsBinded);
        }

        //收费方案
        Fee fee = feeService.getEntity(new String[]{"device_fee_id"},
                new Object[]{deviceDTO.getFeeId()});
        if (null == fee) {
            throw new ServiceException(DeviceCode.NoFee);
        }

        //检查站场
        Station station = stationService.getEntity(new String[]{"device_station_id"},
                new Object[]{deviceDTO.getStationId()});
        if (null == station) {
            throw new ServiceException(DeviceCode.NoStation);
        }

        Pile newPile = new Pile();
        newPile.setDevicePileId(deviceDTO.getDeviceId());
        newPile.setDeviceStationId(deviceDTO.getStationId());
        newPile.setDeviceFeeId(deviceDTO.getFeeId());
        newPile.setPlatformMerchantId(sessionUserService.getTokenUserId());
        service.save(newPile);

        try {
            if (DeviceTypeEnum.EV.name().equals(pile.getDeviceType()) && StringUtil.equals(pile.getDeviceStatus(),DeviceEnum.DeviceStatus.Online.name())) {
                service.remoteUpdatePrice(newPile);
            }
        }catch (Exception ex){
            log.error("更价出错：{}",ex.getMessage());
        }
    }

    /**
     * 设备回收
     *
     * @param code
     */
    @Transactional
    public void recover(String code) {
        Pile pile = service.getEntity(new String[]{"platform_merchant_id", "code"},
                new Object[]{sessionUserService.getTokenUserId(), code});
        if (null == pile) {
            throw new ServiceException(DeviceCode.NoPile);
        }
        if(pile.getDeviceStationId().equals("")) {
            throw  new ServiceException(DeviceCode.PileNoRunning);
        }

        Pile newPile = BeanUtil.copyProperties(pile, Pile.class,
                "devicePileId", "deviceStationId");
        if (orderService.getEntity(new String[]{"device_code", "status"}, new Object[]{pile.getCode(), OrderEnum.Status.Charging.name()}) != null) {
            throw new ServiceException(DeviceCode.ChargingNoMoveAndRecycle);
        }

        boolean result = service.delete(pile.getDevicePileId());

        newPile.setRecycleTime(new Date());
        String user_type = sessionUserService.getTokenUser().getType();
        if(user_type.equals("merchant")) {
            newPile.setDeviceStationId("");
            newPile.setDeviceFeeId("");
        }
        result = result && service.save(newPile);

        result = result && gunService.delete("device_pile_id", pile.getDevicePileId());
        for (int index = 0; index < newPile.getGunCount(); index++) {
            Gun gun = new Gun();
            gun.setDevicePileId(newPile.getDevicePileId());
            gun.setPort(index + 1);
            gun.setCreateTime(new Date());
            result = result && gunService.save(gun);
        }

        if(!result){
            throw new ServiceException(DeviceCode.RecycleFailure);
        }
    }

    /**
     * 设备转移
     *
     * @param deviceDTO
     */
    @Transactional
    public void transfer(DeviceDTO deviceDTO) {
        Pile pile = service.getEntity(new String[]{"platform_merchant_id", "device_pile_id"},
                new Object[]{sessionUserService.getTokenUserId(), deviceDTO.getDeviceId()});
        if (null == pile) {
            throw new ServiceException(DeviceCode.NoPile);
        }

        if(pile.getDeviceStationId().equals(deviceDTO.getStationId()) && pile.getDeviceFeeId().equals(deviceDTO.getFeeId())) {
            throw new ServiceException(DeviceCode.PileNoNeedTransfer);
        }

        if (orderService.getEntity(new String[]{"device_code", "status"}, new Object[]{pile.getCode(), OrderEnum.Status.Charging.name()}) != null) {
            throw new ServiceException(DeviceCode.ChargingNoMoveAndRecycle);
        }

        Pile newPile = BeanUtil.copyProperties(pile, Pile.class,
                "devicePileId", "deviceStationId");
        Station station = stationService.getEntity(new String[]{"platform_merchant_id", "device_station_id"},
                new Object[]{sessionUserService.getTokenUserId(), deviceDTO.getStationId()});
        if (null == station) {
            throw new ServiceException(DeviceCode.NoStation);
        }

        newPile.setComId(station.getComId());
        newPile.setDeviceStationId(deviceDTO.getStationId());
        newPile.setPlatformMerchantId(station.getPlatformMerchantId());
        newPile.setDeviceFeeId(deviceDTO.getFeeId());
        boolean result = service.save(newPile);

        result = result && service.delete(pile.getDevicePileId());

        result = result && gunService.delete("device_pile_id", pile.getDevicePileId());
        for (int index = 0; index < newPile.getGunCount(); index++) {
            Gun gun = new Gun();
            gun.setDevicePileId(newPile.getDevicePileId());
            gun.setPort(index + 1);
            gun.setCreateTime(new Date());
            result = result && gunService.save(gun);
        }

        if(!result){
            throw new ServiceException(DeviceCode.TransferFailure);
        }

        try {
            if (DeviceTypeEnum.EV.name().equals(pile.getDeviceType()) && StringUtil.equals(pile.getDeviceStatus(),DeviceEnum.DeviceStatus.Online.name())) {

                if(!StringUtil.equals(pile.getDeviceFeeId(),deviceDTO.getFeeId())) {
                    service.remoteUpdatePrice(pile);
                }
            }
        }catch (Exception ex){
            log.error("更价出错：{}",ex.getMessage());
        }
    }

    /**
     * 下发至运营商
     *
     * @param deliveryDTO
     */
    public void arrangeToMerchant(DeliveryDTO deliveryDTO) {
        String platformMerchantId = StringUtil.getTrim(deliveryDTO.getMerchantId());

        String comId = getComId();
        Merchant merchant = merchantService.getEntity(platformMerchantId);
        if (null == merchant) {
            throw new ServiceException(PlatformCode.MerchantNotExist);
        }

        Pile pile = service.getEntity(new String[]{"code","platform_merchant_id"}, new Object[]{deliveryDTO.getCode(),sessionUserService.getTokenUserId()});
        if (null == pile) {
            throw new ServiceException(DeviceCode.NoPile);
        }

        //已下发到网点的设备不能再下发给下级运营商
        if (StrUtil.isNotEmpty(pile.getDeviceStationId())) {
            throw new ServiceException(DeviceCode.ArrangedStation);
        }

        pile.setDeliveryTime(new Date());
        pile.setPlatformMerchantId(platformMerchantId);
        pile.setComId(comId);
        service.save(pile);
    }

    /**
     * 校验数据权限
     * @param id
     */
    private void checkPermission(String id){
        Pile entity = service.getEntity(id);
        if(null == entity)
            throw new ServiceException(DeviceCode.NoDevice);

        if(!StringUtil.equals(sessionUserService.getTokenUserId(),entity.getPlatformMerchantId()))
            throw new ServiceException(CommonCode.NoDataPermission);
    }
}
